package com.zz.framework.core.http

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.internal.`$Gson$Types`
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import com.zz.framework.core.Kernel
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.lang.reflect.Type

/**
 * Copyright © 2020 zanezhao All rights reserved.
 * Created by zanezhao on 2020/3/1 1:16 PM.
 * @author: zanezhao 1820022519@qq.com
 * @version: V1.0
 */

object BaseRetrofit {
    fun create(baseUrl: String): Retrofit {
        return Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(
                GsonConverterFactory
                    .create(gsonNullToDefault())
            )
//            .addConverterFactory(
//             Json.asConverterFactory("application/json; charset=UTF8".toMediaType()))
            .client(Kernel.retrofitConfig.initOkHttpClient())
            .build()
    }
}

fun gsonNullToDefault(): Gson = GsonBuilder()
    .registerTypeAdapterFactory(GsonDefaultAdapterFactory())
    .create()


class GsonDefaultAdapterFactory : TypeAdapterFactory {
    override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
        return when (type.type) {
            String::class.java -> createStringAdapter()
//            Int::class.java, Int::class.javaObjectType -> createIntAdapter()
//            Double::class.java, Double::class.javaObjectType -> createDoubleAdapter()
//            Float::class.java, Float::class.javaObjectType -> createFloatAdapter()
//            Boolean::class.java, Boolean::class.javaObjectType -> createBooleanAdapter()
//            Long::class.java, Long::class.javaObjectType -> createLongAdapter()
//            else -> if (type.rawType == List::class.java || type.rawType == Collection::class.java) {
//                createCollectionAdapter(type, gson)
//            } else {
//                null
//            }
            else->null
        }
    }

    /**
     * null替换成空List
     */
    private fun <T : Any> createCollectionAdapter(
        type: TypeToken<T>,
        gson: Gson
    ): TypeAdapter<T>? {
        val rawType = type.rawType
        if (!Collection::class.java.isAssignableFrom(rawType)) {
            return null
        }
        val elementType: Type = `$Gson$Types`.getCollectionElementType(type.type, rawType)
        val elementTypeAdapter: TypeAdapter<Any> =
            gson.getAdapter(TypeToken.get(elementType)) as TypeAdapter<Any>
        return object : TypeAdapter<Collection<Any>>() {
            override fun write(writer: JsonWriter, value: Collection<Any>?) {
                writer.beginArray()
                value?.forEach {
                    elementTypeAdapter.write(writer, it)
                }
                writer.endArray()
            }

            override fun read(reader: JsonReader): Collection<Any> {
                val list = mutableListOf<Any>()
                // null替换为空list
                if (reader.peek() == JsonToken.NULL) {
                    reader.nextNull()
                    return list
                }
                reader.beginArray()
                while (reader.hasNext()) {
                    val element = elementTypeAdapter.read(reader)
                    list.add(element)
                }
                reader.endArray()
                return list
            }
        } as TypeAdapter<T>
    }

    /**
     * null 替换成空字符串
     */
    private fun <T : Any> createStringAdapter(): TypeAdapter<T> {
        return object : TypeAdapter<String>() {
            override fun write(writer: JsonWriter, value: String?) {
                if (value == null) {
                    writer.value("")
                } else {
                    writer.value(value)
                }
            }

            override fun read(reader: JsonReader): String {
                return if (reader.peek() == JsonToken.NULL) {
                    reader.nextNull()
                    ""
                } else {
                    reader.nextString()
                }
            }
        } as TypeAdapter<T>
    }

    private fun <T : Any> createIntAdapter(): TypeAdapter<T> {
        return object : TypeAdapter<Int>() {
            override fun write(writer: JsonWriter, value: Int?) {
                writer.value(value ?: 0)
            }

            override fun read(reader: JsonReader): Int {
                return if (reader.peek() == JsonToken.NULL) {
                    reader.nextNull()
                    0
                } else {
                    reader.nextInt()
                }
            }
        } as TypeAdapter<T>
    }

    private fun <T : Any> createDoubleAdapter(): TypeAdapter<T> {
        return object : TypeAdapter<Double>() {
            override fun write(writer: JsonWriter, value: Double?) {
                writer.value(value ?: 0.0)
            }

            override fun read(reader: JsonReader): Double {
                return if (reader.peek() == JsonToken.NULL) {
                    reader.nextNull()
                    0.0
                } else {
                    reader.nextDouble()
                }
            }
        } as TypeAdapter<T>
    }

    private fun <T : Any> createFloatAdapter(): TypeAdapter<T> {
        return object : TypeAdapter<Float>() {
            override fun write(writer: JsonWriter, value: Float?) {
                writer.value(value ?: 0f)
            }

            override fun read(reader: JsonReader): Float {
                return if (reader.peek() == JsonToken.NULL) {
                    reader.nextNull()
                    0f
                } else {
                    reader.nextDouble().toFloat()
                }
            }
        } as TypeAdapter<T>
    }

    private fun <T : Any> createBooleanAdapter(): TypeAdapter<T> {
        return object : TypeAdapter<Boolean>() {
            override fun write(writer: JsonWriter, value: Boolean?) {
                writer.value(value ?: false)
            }

            override fun read(reader: JsonReader): Boolean {
                return if (reader.peek() == JsonToken.NULL) {
                    reader.nextNull()
                    false
                } else {
                    reader.nextBoolean()
                }
            }
        } as TypeAdapter<T>
    }

    private fun <T : Any> createLongAdapter(): TypeAdapter<T> {
        return object : TypeAdapter<Long>() {
            override fun write(writer: JsonWriter, value: Long?) {
                writer.value(value ?: 0L)
            }

            override fun read(reader: JsonReader): Long {
                return if (reader.peek() == JsonToken.NULL) {
                    reader.nextNull()
                    0L
                } else {
                    reader.nextLong()
                }
            }
        } as TypeAdapter<T>
    }
}
